package com.shanhesoft.java.common.listener;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shanhesoft.java.common.core.util.StringUtil;
import com.shanhesoft.java.common.ws.SubmissionWebSocketServer;
import com.shanhesoft.java.modules.exam.domain.Answer;
import com.shanhesoft.java.modules.exam.domain.OjJudgers;
import com.shanhesoft.java.modules.exam.domain.OjProblemCheckpoints;
import com.shanhesoft.java.modules.exam.domain.OjSubmissions;
import com.shanhesoft.java.modules.exam.domain.PaperQue;
import com.shanhesoft.java.modules.exam.domain.dto.AnswerDto;
import com.shanhesoft.java.modules.exam.domain.dto.ExaminationRecordDto;
import com.shanhesoft.java.modules.exam.service.AnswerService;
import com.shanhesoft.java.modules.exam.service.ExaminationRecordService;
import com.shanhesoft.java.modules.exam.service.OjJudgersService;
import com.shanhesoft.java.modules.exam.service.OjProblemCheckpointsService;
import com.shanhesoft.java.modules.exam.service.OjSubmissionsService;
import com.shanhesoft.java.modules.exam.service.PaperQueService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class QueueConsumerListener
{
	@Autowired
	private OjJudgersService ojJudgersService;
	@Autowired
	private OjSubmissionsService ojSubmissionsService;
	@Autowired
	private AnswerService answerService;
	@Autowired
	private ExaminationRecordService recordService;
	@Autowired
	private PaperQueService paperQueService;
	@Autowired
	private OjProblemCheckpointsService ojProblemCheckpointsService;

	private Map<String, Object> map = new ConcurrentHashMap<>();

    //queue模式的消费者
    @JmsListener(destination="${spring.activemq.queue-name}", containerFactory="queueListener")
    public void readActiveQueue(Map<String, Object> message) {
        System.out.println("queue接受到：" + message);
        log.info("queue接受到：" + message);
        String event = (String) message.get("event");
        switch (event) {
		case "KeepAlive"://心跳
			String judgerName = (String) message.get("judgerName");
			String description = (String) message.get("description");
			Long heartbeatTime = (Long) message.get("heartbeatTime");
			Object lastHeartbeatTime = map.get("lastHeartbeatTime");
			if(lastHeartbeatTime != null &&
					heartbeatTime.longValue() - ((Long)lastHeartbeatTime).longValue() >= 3*25*1000) {
				QueryWrapper<OjJudgers> queryWrapper = new QueryWrapper<OjJudgers>();
				queryWrapper.eq("name", judgerName);
				OjJudgers ojJudgers = ojJudgersService.getOne(queryWrapper);
				ojJudgers.setStatus(0L);
				ojJudgersService.updateById(ojJudgers);
			}
			map.put("lastHeartbeatTime", heartbeatTime);
			break;

		case "ErrorOccurred"://当系统错误发生时通知用户
			String submissionId = (String) message.get("submissionId");
			try {
				SubmissionWebSocketServer.sendInfo("判题器系统错误，请联系管理员！", submissionId);
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;

		case "CompileFinished"://当编译阶段结束时通知用户
			submissionId = (String) message.get("submissionId");
			Boolean isSuccessful = (Boolean) message.get("isSuccessful");
			String log = (String)message.get("log");
			try {
				SubmissionWebSocketServer.sendInfo(log, submissionId);
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;

		case "TestPointFinished"://实时返回评测结果
			submissionId = (String) message.get("submissionId");
			String checkpointId = (String)message.get("checkpointId");
			String runtimeResult = (String)message.get("runtimeResult");
			Integer usedTime = (Integer)message.get("usedTime");
			Integer usedMemory = (Integer)message.get("usedMemory");
			Integer score = (Integer)message.get("score");
			String msg = new StringBuffer("用例编号："+checkpointId).append("\t").append("运行结果："+runtimeResult).append("\t")
			.append("耗时："+usedTime).append("\t").append("使用内存："+usedMemory).append("\t").append("得分："+score).toString();
			try {
				SubmissionWebSocketServer.sendInfo(msg, submissionId);
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;

		case "AllTestPointsFinished"://最终程序评测结果
			submissionId = (String) message.get("submissionId");
			runtimeResult = (String)message.get("runtimeResult");
			Integer totalTime = (Integer)message.get("totalTime");
			Integer maxMemory = (Integer)message.get("maxMemory");
			Integer totalScore = (Integer)message.get("totalScore");
			OjSubmissions ojSubmissions = ojSubmissionsService.getById(submissionId);
			if(ObjectUtil.isNotEmpty(ojSubmissions) && StringUtil.isNotBlank(ojSubmissions.getAnswerId())) {
				AnswerDto answerDto = answerService.getOneDto(ojSubmissions.getAnswerId());
				ExaminationRecordDto recordDto = recordService.getOneDto(answerDto.getExamRecordId());
				if("AC".equals(ojSubmissions.getSubmissionJudgeResult()) ||
						"WA".equals(ojSubmissions.getSubmissionJudgeResult())) {
					QueryWrapper<PaperQue> queryWrapper = new QueryWrapper<PaperQue>();
					queryWrapper.eq("paper_id", recordDto.getPaperId());
					queryWrapper.eq("que_id", answerDto.getQueId());
					queryWrapper.eq("que_type", answerDto.getQueType());
					PaperQue paperQue = paperQueService.getOne(queryWrapper);
					QueryWrapper<OjProblemCheckpoints> cpWrapper = new QueryWrapper<>();
					cpWrapper.eq("problem_id", answerDto.getQueId());
					List<OjProblemCheckpoints> list = ojProblemCheckpointsService.list(cpWrapper );
					int sumCpScore = 0;
					for (OjProblemCheckpoints ojProblemCheckpoints : list) {
						sumCpScore += ojProblemCheckpoints.getCheckpointScore().intValue();
					}
					answerDto.setScore(paperQue.getScore().intValue()*totalScore.intValue()/sumCpScore);
					answerDto.setAnswerType("0"); // 正确
				}

				answerDto.setEndTime(new Date());
				answerService.saveOrUpdate(answerDto);

				// 算总分、计算正确数错误数
				if(null == recordDto.getScore()) {
					recordDto.setScore(0L);
				}
				if(null == answerDto.getScore()) {
					answerDto.setScore(0);
				}
				int oldScore = answerDto.getScore() == null ? 0 : answerDto.getScore();
				if(oldScore > 0 && recordDto.getScore() > oldScore) { // 默认认为总分大于旧得分
					recordDto.setScore(recordDto.getScore() - oldScore + answerDto.getScore());
				} else {
					recordDto.setScore(recordDto.getScore() + answerDto.getScore());
				}

				// 统计对错数
				QueryWrapper<Answer> answerQueryWrapper = new QueryWrapper<Answer>();
				answerQueryWrapper.eq("answer_type", "0");
				answerQueryWrapper.eq("exam_record_id", recordDto.getId());
				int rightCount = answerService.count(answerQueryWrapper);
				answerQueryWrapper = new QueryWrapper<Answer>();
				answerQueryWrapper.eq("answer_type", "1");
				answerQueryWrapper.eq("exam_record_id", recordDto.getId());
				int errorCount = answerService.count(answerQueryWrapper);

				recordDto.setCorrectNumber(Long.parseLong(""+rightCount));
				recordDto.setIncorrectNumber(Long.parseLong(""+errorCount));

				recordService.saveOrUpdate(recordDto);
			}
			ojSubmissions.getAnswerId();
			msg = new StringBuffer("运行结果："+runtimeResult).append("\t")
					.append("总耗时："+totalTime).append("\t").append("总内存："+maxMemory)
					.append("\t").append("总分："+totalScore).toString();
			try {
				SubmissionWebSocketServer.sendInfo(msg, submissionId);
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;

		default:
			break;
		}
    }
}
